﻿//==============================================================
//  Create by whl at 4/11/2014 11:02:31 AM.
//  Version 1.0
//  
//==============================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cn.Finder.SDKFramework.Util;
using Cn.Finder.SDKFramework.Request;
using System.Xml;
using Jayrock.Json.Conversion;
using Cn.Finder.SDKFramework.Parser;
using Cn.Finder.SDKFramework.Response;
using System.Diagnostics;
using Cn.Finder.SDKFramework.Domain;
using System.Threading;

namespace Cn.Finder.SDKFramework
{
    public class DefaultClient : IClient
    {
        public const string APP_KEY = "app_key";
        private string appKey;
        private string appSecret;

        /// <summary>
        /// 是否启用对返回字符串进行解析 XML或者JSON ，如果为false，那么不解析 直接使用原始数据
        /// </summary>
        private bool disableParser;
        private bool disableTrace;
        /// <summary>
        /// 返回数据格式
        /// </summary>
        private string format;



        public const string FORMAT = "format";
        public const string FORMAT_XML = "xml";
        public const string FORMAT_JSON = "json";
        public const string METHOD = "method";
        public const string PARTNER_ID = "partner_id";
        public const string SDK_VERSION = "api-sdk-net-20140410";
        private string serverUrl;
        public const string SESSION = "session";
        public const string SIGN = "sign";
        public const string VERSION = "v";

        private IDictionary<string, string> systemParameters;
        public const string TIMESTAMP = "timestamp";
        private ILogger apsLogger;
        
        private WebUtils webUtils;


        /// <summary>
        /// 默认客户端 
        /// </summary>
        /// <param name="serverUrl">服务器地址</param>
        /// <param name="appKey">应用KEY</param>
        /// <param name="appSecret">应用秘钥</param>
        public DefaultClient(string serverUrl, string appKey, string appSecret)
        {
            this.format = "json";
            this.appKey = appKey;
            this.appSecret = appSecret;
            this.serverUrl = serverUrl;
            this.webUtils = new WebUtils();
            this.apsLogger = new DefaultLogger();
        }
        /// <summary>
        /// 默认客户端 
        /// </summary>
        /// <param name="serverUrl">服务器地址</param>
        /// <param name="appKey">应用KEY</param>
        /// <param name="appSecret">应用秘钥</param>
        /// <param name="format">返回数据格式</param>
        public DefaultClient(string serverUrl, string appKey, string appSecret, string format)
            : this(serverUrl, appKey, appSecret)
        {
            this.format = format;
        }
        public DefaultClient(string serverUrl, string appKey, string appSecret, string format,bool disableParser)
            : this(serverUrl, appKey, appSecret)
        {
            this.format = format;
            this.disableParser = disableParser;
        }
        public DefaultClient(string serverUrl, string appKey, string appSecret, bool disableParser)
            : this(serverUrl, appKey, appSecret)
        {
           
            this.disableParser = disableParser;
        }

        /// <summary>
        /// 创建错误消息到ApsResponse对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="errCode"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        private T createErrorResponse<T>(string errCode, string errMsg) where T: ApiResponse
        {
            T local = Activator.CreateInstance<T>();
            //local.ErrCode = errCode;
            //local.ErrMsg = errMsg;

           // local.Message.StatusCode = int.Parse(errCode);
            local.Message.StatusCode = Message.StatusCode_ClientError;
            local.Message.Msg = errMsg;
            if (FORMAT_XML.Equals(this.format))
            {
                XmlDocument document = new XmlDocument();
                XmlElement newChild = document.CreateElement("error_response");

                XmlElement eleMessage = document.CreateElement("message");

                XmlElement elementCode = document.CreateElement("statusCode");
                elementCode.InnerText = errCode;
                eleMessage.AppendChild(elementCode);

                XmlElement elementMsg = document.CreateElement("msg");
                elementMsg.InnerText = errMsg;
                eleMessage.AppendChild(elementMsg);

                XmlElement elementDetail = document.CreateElement("detail");
                elementMsg.InnerText = errMsg;
                eleMessage.AppendChild(elementDetail);


                document.AppendChild(eleMessage);
                local.Body = document.OuterXml;
                return local;
            }
            IDictionary<string, object> messageDict = new Dictionary<string, object>();

            IDictionary<string, object> dictionary = new Dictionary<string, object>();
            dictionary.Add("statusCode", errCode);
            dictionary.Add("msg", errMsg);

            messageDict.Add("message", dictionary);


            IDictionary<string, object> error_response_dict = new Dictionary<string, object>();
            error_response_dict.Add("error_response", messageDict);

           
           // string str = JsonConvert.ExportToString(error_response_dict);
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(error_response_dict);
            
            local.Body = str;
            return local;
        }



        private T DoExecute<T>(IRequest<T> request, string session, DateTime timestamp) where T: ApiResponse
        {
            T resp=default(T);
           // T resp;
            //resp = new T();
            try
            {
                //请求参数验证
                request.Validate();
            }
            catch (ApiException exception)
            {
                return this.createErrorResponse<T>(exception.ErrorCode, exception.ErrorMsg);
            }
            IDictionary<String,String> reqParams = request.GetParameters();
            ApiDictionary parameters = new ApiDictionary(reqParams);


            // 从 Assembly中获取 版本信息
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string versionStr = string.Format("{0}.{1}", fvi.ProductMajorPart, fvi.ProductMinorPart);


            parameters.Add(METHOD, request.GetApiName());
           // parameters.Add(VERSION, "1.0");
            parameters.Add(VERSION,versionStr);
            parameters.Add(APP_KEY, this.appKey);
            parameters.Add(FORMAT, this.format);
            parameters.Add(PARTNER_ID, SDK_VERSION);
            parameters.Add(TIMESTAMP, timestamp);

            parameters.Add(SESSION, session==null?"":session);

            parameters.AddAll(this.systemParameters);

            //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
            //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));
            
            
            string strGetUrl = this.webUtils.BuildGetUrl(this.serverUrl, parameters);

           

            // updated by dragon  20140609
         //   string dataJsonstr = JsonConvert.ExportToString(reqParams);


            string dataJsonstr = Newtonsoft.Json.JsonConvert.SerializeObject(reqParams);
            parameters.Add("data", dataJsonstr);
           
            try
            {
                T respTmp = null;
                string retStr;

                if (request is IUploadRequest<T>)
                {//  二进制(文件、图片)请求
                    IDictionary<string, FileItem> fileParams = ApiUtils.CleanupDictionary<FileItem>(((IUploadRequest<T>)request).GetFileParameters());
                    if (fileParams != null && fileParams.Count > 0)
                    {
                        /*IEnumerator<KeyValuePair<string,FileItem>> itor = fileParams.GetEnumerator();

                        while(itor.MoveNext()){
                           KeyValuePair<string,FileItem> pair =  itor.Current;
                           string key = pair.Key;
                            FileItem value = pair.Value;
                            reqParams.Add(key, value.GetFileName());
                        }*/

                    }

                    retStr = this.webUtils.DoPost(this.serverUrl, parameters, fileParams);
                }
                else if (request is StreamRequest<T>)
                {


                    retStr = this.webUtils.BuildGetUrl(this.serverUrl, parameters);
                }
                else
                {


                    //发送普通文本请求
                    retStr = this.webUtils.DoPost(this.serverUrl, parameters);

                    //    retStr ="<?xml version=\"1.0\" encoding=\"utf-8\" ?><error_response><code>26</code><msg>Missing session</msg></error_response><!--vsandbox067146.cm4.tbsite.net-->";
                    //xml数据测试
                    // retStr = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><queryResult><pageIndex>2</pageIndex><pageSize>10</pageSize><resultList><user><id>1</id></user><user><id>2</id></user></resultList></queryResult>";

                    //retStr = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><queryResult><pageIndex>2</pageIndex><pageSize>10</pageSize><resultList><user><id>1</id><name>哈哈</name></user><user><id>2</id><name>地方</name></user></resultList></queryResult>";

                    //json 数据测试
                    //retStr = "{pageIndex:2,pageSize:10,resultList:{user:[{id:1,name:\"龙哥\"},{id:2,name:\"龙爷\"}]},message:{statusCode:200,msg:\"请求成功\"}}";

                    //retStr = "{pageIndex:2,pageSize:10,resultList:[{id:1,name:\"龙哥\"},{id:2,name:\"龙爷\"}]}";
                }
                if (this.disableParser)
                {
                    respTmp = Activator.CreateInstance<T>();
                    respTmp.Body = retStr;
                }
                else if (FORMAT_XML.Equals(this.format))
                {
                    IParser parser = new XmlParser();
                    respTmp = parser.Parse<T>(retStr);
                }
                else
                {
                    IParser parser = new JsonParser();
                    respTmp = parser.Parse<T>(retStr);
                }
                if (!this.disableTrace && respTmp.Message.StatusCode != Message.StatusCode_OK)
                {
                    this.apsLogger.Warn(new StringBuilder(strGetUrl).Append(" response error!\r\n").Append(respTmp.Body).ToString());
                }
                resp = respTmp;
            }
            catch (Exception exp)
            {
                if (!this.disableTrace)
                {
                    this.apsLogger.Error(new StringBuilder(strGetUrl).Append(" request error!\r\n").Append(exp.StackTrace).ToString());
                }
                // throw exp;

                string respStrNotFound = "{message:{statusCode:404,msg:\"调用失败，查看服务器是否开启或者网络是否连接\",detail:null},pageIndex:1,pageSize:10,totalRecord:0,pageCount:0,entities:[]}";
                IParser parser = new JsonParser();
                resp = parser.Parse<T>(respStrNotFound);
                
            }
            //if(OnResponse!=null)
            //    OnResponse(resp);
           // finally
           // {
                return resp;
          //  }
        }

       

        /// <summary>
        /// 异步执行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        //public void ExecuteInThread<T>(IRequest<T> request) where T : ApiResponse
        //{
        
        //    ParameterizedThreadStart parameterizedThreadStart=new ParameterizedThreadStart(ExecuteInThreadHandle);

        //    Thread requestThread = new Thread(parameterizedThreadStart);

        //    requestThread.Start(request);
        //}

        //private void ExecuteInThreadHandle(object param)
        //{
        //    SearchRequest<ApiResponse> request = param as SearchRequest<ApiResponse>;
        //    Execute(request);
        //}

        /// <summary>
        /// 返回请求 字符串数据 只用作测试
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="session"></param>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public string Execute(ApiDictionary parameters, string session, DateTime timestamp,string method) 
        {
           

            //生成JSON
            //string jsonStr = JsonConvert.ExportToString(parameters);
            string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);
            
            // 从 Assembly中获取 版本信息
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string versionStr = string.Format("{0}.{1}", fvi.ProductMajorPart, fvi.ProductMinorPart);

          
            parameters.Add(METHOD, method);
            // parameters.Add(VERSION, "1.0");
            parameters.Add(VERSION, versionStr);
            parameters.Add(APP_KEY, this.appKey);
            parameters.Add(FORMAT, this.format);
            parameters.Add(PARTNER_ID, SDK_VERSION);
            parameters.Add(TIMESTAMP, timestamp);

            parameters.Add(SESSION, session == null ? "" : session);

            parameters.AddAll(this.systemParameters);

            //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
            //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));


            



            // updated by dragon  20140609
            string dataJsonstr = jsonStr;
            parameters.Add("data", dataJsonstr);

            string strGetUrl = this.webUtils.BuildGetUrl(this.serverUrl, parameters);


            try
            {
                string retStr;
               
                if (true)
                {

                    //发送普通文本请求
                    retStr = this.webUtils.DoPost(this.serverUrl, parameters);

             
                }
                return retStr;
               
            }
            catch (Exception exp)
            {
                if (!this.disableTrace)
                {
                    this.apsLogger.Error(new StringBuilder(strGetUrl).Append(" request error!\r\n").Append(exp.StackTrace).ToString());
                }
                throw exp;
            }
          
        }



        /// <summary>
        /// 下载数据流
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="session"></param>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public string ExecuteFileStream(ApiDictionary parameters, string session, DateTime timestamp, string method)
        {


            //生成JSON
            //string jsonStr = JsonConvert.ExportToString(parameters);
            string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);

            // 从 Assembly中获取 版本信息
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string versionStr = string.Format("{0}.{1}", fvi.ProductMajorPart, fvi.ProductMinorPart);


            parameters.Add(METHOD, method);
            // parameters.Add(VERSION, "1.0");
            parameters.Add(VERSION, versionStr);
            parameters.Add(APP_KEY, this.appKey);
            parameters.Add(FORMAT, this.format);
            parameters.Add(PARTNER_ID, SDK_VERSION);
            parameters.Add(TIMESTAMP, timestamp);

            parameters.Add(SESSION, session == null ? "" : session);

            parameters.AddAll(this.systemParameters);

            //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
            //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));






            // updated by dragon  20140609
            string dataJsonstr = jsonStr;
            parameters.Add("data", dataJsonstr);

            string strGetUrl = this.webUtils.BuildGetUrl(this.serverUrl, parameters);



            try
            {
                string retStr;


                retStr = this.webUtils.BuildGetUrl(this.serverUrl, parameters);


                return retStr;

            }
            catch (Exception exp)
            {
                if (!this.disableTrace)
                {
                    this.apsLogger.Error(new StringBuilder(strGetUrl).Append(" request error!\r\n").Append(exp.StackTrace).ToString());
                }
                throw exp;
            }

        }



        /// <summary>
        /// 测试用的所有的通用请求 普通文本和文件上传
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="fileParams"></param>
        /// <param name="session"></param>
        /// <param name="timestamp"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public string Execute(ApiDictionary parameters, IDictionary<string, FileItem> fileParams, string session, DateTime timestamp, string method)
        {
            //生成JSON
            //string jsonStr = JsonConvert.ExportToString(parameters);
            string jsonStr = "";

            if (fileParams != null && fileParams.Count > 0)
            {
                IEnumerator<KeyValuePair<string, FileItem>> itor = fileParams.GetEnumerator();

                while (itor.MoveNext())
                {
                    KeyValuePair<string, FileItem> pair = itor.Current;
                    string key = pair.Key;
                    FileItem value = pair.Value;
                    parameters.Add(key, value.GetFileName());
                }

                jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);
               
            }
            else
            {
                jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);
            }

            // 从 Assembly中获取 版本信息
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string versionStr = string.Format("{0}.{1}", fvi.ProductMajorPart, fvi.ProductMinorPart);


            parameters.Add(METHOD, method);
            // parameters.Add(VERSION, "1.0");
            parameters.Add(VERSION, versionStr);
            parameters.Add(APP_KEY, this.appKey);
            parameters.Add(FORMAT, this.format);
            parameters.Add(PARTNER_ID, SDK_VERSION);
            parameters.Add(TIMESTAMP, timestamp);

            parameters.Add(SESSION, session == null ? "" : session);

            parameters.AddAll(this.systemParameters);

            //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
            //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));



            


            // updated by dragon  20140609
            string dataJsonstr = jsonStr;
            parameters.Add("data", dataJsonstr);

            string strGetUrl = this.webUtils.BuildGetUrl(this.serverUrl, parameters);


            try
            {
                string retStr;

                if (true)
                {

                    //发送带文件请求
                    retStr = this.webUtils.DoPost(this.serverUrl, parameters, fileParams);
                
                }
                return retStr;

            }
            catch (Exception exp)
            {
                if (!this.disableTrace)
                {
                    this.apsLogger.Error(new StringBuilder(strGetUrl).Append(" request error!\r\n").Append(exp.StackTrace).ToString());
                }
                throw exp;
            }
        }


        /// <summary>
        /// 构建 GET 请求数据
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="session"></param>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public string  BuildReqGetUrlString(ApiDictionary parameters, string session, DateTime timestamp,string method) 
        {
            

            //生成JSON
            //string jsonStr = JsonConvert.ExportToString(parameters);

            string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);

            // 从 Assembly中获取 版本信息
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string versionStr = string.Format("{0}.{1}", fvi.ProductMajorPart, fvi.ProductMinorPart);

           

            parameters.Add(METHOD, method);
            // parameters.Add(VERSION, "1.0");
            parameters.Add(VERSION, versionStr);
            parameters.Add(APP_KEY, this.appKey);
            parameters.Add(FORMAT, this.format);
            parameters.Add(PARTNER_ID, SDK_VERSION);
            parameters.Add(TIMESTAMP, timestamp);

            parameters.Add(SESSION, session == null ? "" : session);

            parameters.AddAll(this.systemParameters);

            //参数签名   appSecret+参数+appSecret  暂时不需要 加快处理速度
            //parameters.Add(SIGN, ApiUtils.SignRequest(parameters, this.appSecret));






            // updated by dragon  20140609
            string dataJsonstr = jsonStr;
            parameters.Add("data", dataJsonstr);

            string strGetUrl = this.webUtils.BuildGetUrl(this.serverUrl, parameters);
            return strGetUrl;
        }

       
       

        public T Execute<T>(IRequest<T> request) where T: ApiResponse
        {
            return this.Execute<T>(request, "");
        }

        public T Execute<T>(IRequest<T> request, string session) where T : ApiResponse
        {
            return this.Execute<T>(request, session, DateTime.Now);
        }

        public T Execute<T>(IRequest<T> request, string session, DateTime timestamp) where T : ApiResponse
        {
            return this.DoExecute<T>(request, session, timestamp);
           
        }



        public void SetDisableParser(bool disableParser)
        {
            this.disableParser = disableParser;
        }

        public void SetDisableTrace(bool disableTrace)
        {
            this.disableTrace = disableTrace;
        }

        public void SetSystemParameters(IDictionary<string, string> systemParameters)
        {
            this.systemParameters = systemParameters;
        }

        public void SetTimeout(int timeout)
        {
            this.webUtils.Timeout = timeout;
        }

        public void SetApsLogger(ILogger apsLogger)
        {
            this.apsLogger = apsLogger;
        }

        //public event ResponseCallbackDelegate OnResponse;







        //public Response.Generic.ApiResponse<T> Execute<T>(IRequest<Response.Generic.ApiResponse<T>> request) where T : ApiObject
        //{
        //    return Execute<T>(request, "");
        //}

        //public Response.Generic.ApiResponse<T> Execute<T>(IRequest<Response.Generic.ApiResponse<T>> request, string session) where T : ApiObject
        //{
        //    return this.Execute<T>(request, session, DateTime.Now);
        //}

        //public Response.Generic.ApiResponse<T> Execute<T>(IRequest<Response.Generic.ApiResponse<T>> request, string session, DateTime timestamp) where T : ApiObject
        //{
        //    throw new NotImplementedException("未实现");
        //}



    }
}
